package com.aipp.mall.h5.service;

import com.aipp.mall.common.enums.AfterSaleStatus;
import com.aipp.mall.common.enums.OrderRefundStatus;
import com.aipp.mall.common.enums.OrderStatus;
import com.aipp.mall.common.exception.ServerException;
import com.aipp.mall.common.model.Query;
import com.aipp.mall.common.redis.RedisService;
import com.aipp.mall.common.utils.Constants;
import com.aipp.mall.common.utils.DateUtils;
import com.aipp.mall.common.utils.Json;
import com.aipp.mall.common.utils.SecurityUtil;
import com.aipp.mall.h5.domain.dto.DeliveryReq;
import com.aipp.mall.h5.domain.dto.OrderProductListDTO;
import com.aipp.mall.h5.domain.dto.PayNotifyMessageDTO;
import com.aipp.mall.h5.domain.entity.*;
import com.aipp.mall.h5.domain.form.*;
import com.aipp.mall.h5.domain.vo.*;
import com.aipp.mall.h5.mapper.*;
import com.aipp.mall.wechat.WechatPayData;
import com.aipp.mall.wechat.WechatPayUtil;
import com.baomidou.lock.annotation.Lock4j;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.wechat.pay.java.service.partnerpayments.jsapi.model.Transaction;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import lombok.extern.slf4j.Slf4j;
import org.dromara.hutool.core.bean.BeanUtil;
import org.dromara.hutool.core.collection.CollUtil;
import org.dromara.hutool.core.data.id.IdUtil;
import org.dromara.hutool.core.text.StrUtil;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author Administrator
 */
@Service
@Slf4j
public class H5OrderService {

    @Resource
    private MemberAddressMapper memberAddressMapper;

    @Resource
    private SkuMapper skuMapper;

    @Resource
    private ProductMapper productMapper;

    @Resource
    private MemberCartMapper memberCartMapper;

    @Resource
    private OrderMapper orderMapper;

    @Resource
    private OrderItemMapper orderItemMapper;

    @Resource
    private OrderOperateHistoryMapper orderOperateHistoryMapper;

    @Resource
    private OrderItemService orderItemService;

    @Resource
    private OrderOperateHistoryService orderOperateHistoryService;

    @Autowired(required = false)
    private WechatPayService wechatPayService;

    @Resource
    private MemberWechatMapper memberWechatMapper;

    @Resource
    private WechatPaymentHistoryMapper wechatPaymentHistoryMapper;

    @Resource
    private RedisService redisService;

    @Resource
    private AfterSaleMapper aftersaleMapper;

    @Resource
    private AfterSaleItemMapper aftersaleItemMapper;

    @Resource
    private MemberCouponService memberCouponService;
    @Resource
    private WechatPayData wechatPayData;

    @Resource
    private AfterSaleService aftersaleService;


    private record CheckSkuResult(Sku sku, Product product) {
    }

    @Lock4j(name = "h5_order_add:", keys = "#form.member.id")
    @Transactional(rollbackFor = Exception.class)
    public Long submit(OrderSubmitForm form) {
        //只支持快递
        Long addressId = form.getAddressId();
        if (addressId == null) {
            throw new ServerException("收获地址不能为空");
        }
        MemberAddress memberAddress = memberAddressMapper.selectById(addressId);
        if (memberAddress == null) {
            throw new ServerException("收货地址不能为空");
        }
        //sku不能为空
        List<OrderProductListDTO> skuList = form.getSkuList();
        if (CollUtil.isEmpty(skuList)) {
            throw new ServerException("商品SKU信息不能为空");
        }
        //将sku信息转换为 key：skuId ，value：购买数量
        Map<Long, Integer> skuQuantityMap = skuList.stream()
                                                   .collect(Collectors.toMap(OrderProductListDTO::getSkuId, OrderProductListDTO::getQuantity));
        //查询所有sku信息
        Map<Long, Sku> querySkuMap = skuMapper.selectBatchIds(skuList.stream().map(OrderProductListDTO::getSkuId).collect(Collectors.toList()))
                                              .stream().collect(Collectors.toMap(Sku::getId, it -> it));
        //校验优惠券
        BigDecimal couponAmount = BigDecimal.ZERO;
        if (form.getMemberCouponId() != null) {
            MemberCoupon coupon = memberCouponService.selectValidCoupon(form.getMemberCouponId());
            if (coupon == null) {
                throw new ServerException("优惠券未找到");
            }
            //将sku转换成products
            Map<Long, Product> products = calcProductPrice(skuQuantityMap, querySkuMap);
            if (!memberCouponService.judgeCouponCanUse(coupon, products.values())) {
                throw new ServerException("优惠券未达到使用条件");
            }
            couponAmount = coupon.getCouponAmount();
        }
        //计算商品总额、订单总额（订单总金额=商品总金额，因为暂时没有运费等概念）
        BigDecimal productTotalAmount = BigDecimal.ZERO;
        BigDecimal orderTotalAmount = BigDecimal.ZERO;
        for (OrderProductListDTO dto : skuList) {
            CheckSkuResult csr = checkSku(dto, querySkuMap, skuQuantityMap);
            productTotalAmount = productTotalAmount.add(csr.sku().getPrice().multiply(BigDecimal.valueOf(skuQuantityMap.get(csr.sku().getId()))));
            orderTotalAmount = orderTotalAmount.add(csr.sku().getPrice().multiply(BigDecimal.valueOf(skuQuantityMap.get(csr.sku().getId()))));
            dto.setSku(csr.sku());
            dto.setProduct(csr.product());
        }
        LocalDateTime optTime = LocalDateTime.now();

        //生成一个统一的订单号
        Long orderId = IdUtil.getSnowflakeNextId();
        //生产一个payId
        Long payId = IdUtil.getSnowflakeNextId();
        //创建订单
        Order order = new Order();
        order.setPayId(payId);
        order.setId(orderId);
        order.setOrderSn(this.getOrderIdPrefix() + orderId);
        order.setMemberId(SecurityUtil.getMemberId());
        order.setMemberUsername(SecurityUtil.getMemberName());
        order.setPayType(Constants.PayType.WECHAT);
        order.setCouponAmount(couponAmount);
        order.setMemberCouponId(form.getMemberCouponId());
        order.setTotalAmount(orderTotalAmount);
        order.setPurchasePrice(BigDecimal.ZERO);
        order.setFreightAmount(BigDecimal.ZERO);
        BigDecimal subtract = orderTotalAmount.subtract(couponAmount);
        order.setPayAmount(subtract.compareTo(BigDecimal.ZERO) > 0 ? subtract : BigDecimal.ZERO);
        if (order.getPayAmount().compareTo(BigDecimal.ZERO) == 0) {
            order.setStatus(Constants.OrderStatus.SEND);
        } else {
            order.setStatus(Constants.OrderStatus.NOTPAID);
        }
        order.setAftersaleStatus(1);
        order.setReceiverName(memberAddress.getName());
        order.setReceiverPhone(memberAddress.getPhoneHidden());
        order.setReceiverPhoneEncrypted(memberAddress.getPhoneEncrypted());
        order.setReceiverPostCode(memberAddress.getPostCode());
        order.setReceiverProvince(memberAddress.getProvince());
        order.setReceiverCity(memberAddress.getCity());
        order.setReceiverDistrict(memberAddress.getDistrict());
        order.setReceiverProvinceId(memberAddress.getProvinceId());
        order.setReceiverCityId(memberAddress.getCityId());
        order.setReceiverDistrictId(memberAddress.getDistrictId());
        order.setReceiverDetailAddress(memberAddress.getDetailAddress());
        order.setNote(form.getNote());
        order.setConfirmStatus(0);
        order.setDeleteStatus(0);
//        order.setPaymentTime(optTime);
        order.setCreateTime(optTime);
        order.setCreateBy(SecurityUtil.getMemberId());
        int rows = orderMapper.insert(order);
        if (rows < 1) {
            throw new ServerException("订单新增失败");
        }
        // 保存orderItem
        orderItemService.saveOrderItem(optTime, orderId, skuList);
        skuList.forEach(item -> {
            //减少sku的库存
            skuMapper.updateStockById(item.getSkuId(), LocalDateTime.now(), item.getQuantity());
        });
        // 保存订单操作记录
        OrderOperateHistory orderOperateHistory = new OrderOperateHistory();
        orderOperateHistory.setOrderId(orderId);
        orderOperateHistory.setOrderSn(order.getOrderSn());
        orderOperateHistory.setOperateMan(SecurityUtil.getMemberName());
        orderOperateHistory.setOrderStatus(Constants.OrderStatus.NOTPAID);
        orderOperateHistory.setCreateTime(optTime);
        orderOperateHistory.setCreateBy(SecurityUtil.getMemberId());
        rows = orderOperateHistoryMapper.insert(orderOperateHistory);
        if (rows < 1) {
            throw new ServerException("保存订单操作记录失败");
        }
        //若来源为购物车，删除购物车
        if (Constants.OrderFrom.CART.equals(form.getFrom())) {
            List<Long> skuIdList = skuList.stream().map(OrderProductListDTO::getSkuId).collect(Collectors.toList());
            LambdaUpdateWrapper<MemberCart> wrapper = Wrappers.lambdaUpdate();
            wrapper.eq(MemberCart::getMemberId, SecurityUtil.getMemberId());
            wrapper.in(MemberCart::getSkuId, skuIdList);
            rows = memberCartMapper.delete(wrapper);
            if (rows < 1) {
                throw new ServerException("删除购物车失败");
            }
        }
        //当前订单id，接入支付后可返回payId
        //如果是使用了优惠券，更新优惠券状态
        if (form.getMemberCouponId() != null) {
            memberCouponService.updateCouponStatus(form.getMemberCouponId(), orderId);
        }
        return payId;
    }

    public OrderCalcVO addOrderCheck(OrderCreateForm orderCreateForm) {
        OrderCalcVO res = new OrderCalcVO();
        List<SkuViewVO> skuList = new ArrayList<>();
        List<OrderProductListDTO> list = orderCreateForm.getSkuList();
        if (CollUtil.isEmpty(list)) {
            throw new ServerException("商品SKU信息不能为空");
        }
        //将购买的sku信息转化为key：skuId value：数量
        Map<Long, Integer> quantityMap = list.stream()
                                             .collect(Collectors.toMap(OrderProductListDTO::getSkuId, OrderProductListDTO::getQuantity, (v1, v2) -> v2));
        //查询所有sku信息
        Set<Long> collect = list.stream().map(OrderProductListDTO::getSkuId).collect(Collectors.toSet());
        Map<Long, Sku> querySkuMap = skuMapper.selectBatchIds(collect).stream().collect(Collectors.toMap(Sku::getId, it -> it));
        //计算商品总金额、订单总金额
        BigDecimal productTotalAmount = BigDecimal.ZERO;
        BigDecimal orderTotalAmount = BigDecimal.ZERO;
        for (OrderProductListDTO dto : list) {
            CheckSkuResult csr = checkSku(dto, querySkuMap, quantityMap);
            BigDecimal addAmount = csr.sku().getPrice().multiply(BigDecimal.valueOf(dto.getQuantity()));
            //由于目前没有运费等数据，暂时订单总金额=商品总金额了
            productTotalAmount = productTotalAmount.add(addAmount);
            orderTotalAmount = orderTotalAmount.add(addAmount);
            //封装sku信息
            SkuViewVO skuViewVO = new SkuViewVO();
            skuViewVO.setPic(csr.product().getPic());
            skuViewVO.setPrice(csr.sku().getPrice());
            skuViewVO.setProductId(csr.product().getId());
            skuViewVO.setProductName(csr.product().getName());
            skuViewVO.setQuantity(quantityMap.get(csr.sku().getId()));
            skuViewVO.setSkuId(csr.sku().getId());
            skuViewVO.setSpData(csr.sku().getSpData());
            skuList.add(skuViewVO);
        }
        res.setSkuList(skuList);
        res.setOrderTotalAmount(orderTotalAmount);
        res.setProductTotalAmount(productTotalAmount);
        //获取能使用的优惠券列表
        Map<Long, Product> products = calcProductPrice(quantityMap, querySkuMap);
        res.setCouponList(memberCouponService.getCanUseList(products.values()));
        return res;
    }

    private CheckSkuResult checkSku(OrderProductListDTO dto, Map<Long, Sku> querySkuMap, Map<Long, Integer> quantityMap) {
        if (!querySkuMap.containsKey(dto.getSkuId())) {
            throw new ServerException("商品SKU不存在");
        }
        Sku sku = querySkuMap.get(dto.getSkuId());
        //查product
        Product product = productMapper.selectById(sku.getProductId());
        if (product == null) {
            throw new ServerException("商品不存在");
        }
        if (Constants.PublishStatus.UNDERCARRIAGE.equals(product.getPublishStatus())) {
            throw new ServerException("商品" + product.getName() + "已下架");
        }
        if (sku.getStock() < quantityMap.get(sku.getId())) {
            throw new ServerException("库存不足");
        }
        return new CheckSkuResult(sku, product);
    }


    /**
     * 计算产品价格
     *
     * @param quantityMap 用户购买的sku
     * @param querySkuMap 查询数据库SKU
     * @return {@link Map }<{@link Long }, {@link Product }>
     */
    private Map<Long, Product> calcProductPrice(Map<Long, Integer> quantityMap, Map<Long, Sku> querySkuMap) {
        Map<Long, Product> products = new HashMap<>();
        querySkuMap.forEach((k, v) -> {
            Integer count = quantityMap.get(k);
            Long productId = v.getProductId();
            Product product;
            BigDecimal amount = v.getPrice().multiply(BigDecimal.valueOf(count));
            if (products.containsKey(k)) {
                product = products.get(k);
                product.setPrice(amount.add(product.getPrice()));
            } else {
                product = new Product();
                product.setId(productId);
                product.setPrice(amount);
            }
            products.put(k, product);
        });
        return products;
    }


    private String getOrderIdPrefix() {
        LocalDateTime time = LocalDateTime.now();
        return time.format(DateTimeFormatter.ofPattern("yyMMdd")) + "-";
    }

    /**
     * h5订单分页查询
     *
     * @param status 订单状态 -1->全部；0->待付款；1->待发货；2->待收货；-2->售后单
     * @param query  分页
     * @return 结果
     */
    public IPage<H5OrderVO> orderPage(Integer status, Query query) {
        IPage<H5OrderVO> page = orderMapper.orderPage(Page.of(query.getPage(), query.getSize()), status, SecurityUtil.getMemberId());
        // 两个list都没数据那肯定返回空了
        if (page.getRecords().isEmpty()) {
            return new Page<>();
        }
        // 开始组装item了
        // 拿出所有orderId，查item，然后分组 by orderId
        List<Long> idList = page.getRecords().stream().map(H5OrderVO::getOrderId).toList();
        QueryWrapper<OrderItem> orderItemQw = new QueryWrapper<>();
        orderItemQw.in("order_id", idList);
        Map<Long, List<OrderItem>> orderItemMap = orderItemMapper.selectList(orderItemQw).stream()
                                                                 .collect(Collectors.groupingBy(OrderItem::getOrderId));
        return page.convert((item) -> {
            item.setOrderItemList(orderItemMap.get(item.getOrderId()));
            return item;
        });
    }

    public H5OrderVO orderDetail(Long orderId) {
        if (orderId == null) {
            throw new ServerException("未查询到该订单");
        }
        H5OrderVO order = orderMapper.selectOrderDetail(orderId);
        if (order == null) {
            throw new ServerException("未查询到该订单");
        }
        // 组装item
        QueryWrapper<OrderItem> orderItemQw = new QueryWrapper<>();
        orderItemQw.eq("order_id", orderId);
        List<OrderItem> orderItemList = orderItemMapper.selectList(orderItemQw);
        order.setOrderItemList(orderItemList);
        // 如果未付款，计算倒计时
        if (Constants.OrderStatus.NOTPAID.equals(order.getStatus())) {
            // 订单超时时间900s，后面可以配置到字典等
            int time = 900;
            Date addDate = Date.from(order.getCreateTime().plusSeconds(time).atZone(ZoneId.systemDefault()).toInstant());
            if (addDate.after(new Date())) {
                order.setTimeToPay(addDate.getTime());
            }
        }
        return order;
    }

    @Transactional(rollbackFor = Exception.class)
    public void orderCompleteByJob(List<Order> idList) {
        idList.forEach(order -> {
            LocalDateTime optDate = LocalDateTime.now();
            OrderItem queryOrderItem = new OrderItem();
            queryOrderItem.setOrderId(order.getId());
            //更新订单
            order.setStatus(Constants.H5OrderStatus.COMPLETED);
            order.setReceiveTime(optDate);
            order.setConfirmStatus(1);
            order.setUpdateTime(optDate);
            order.setUpdateBy(null);
            orderMapper.updateById(order);
            //创建订单操作记录
            OrderOperateHistory optHistory = new OrderOperateHistory();
            optHistory.setOrderId(order.getId());
            optHistory.setOrderSn(order.getOrderSn());
            optHistory.setOperateMan("后台管理员");
            optHistory.setOrderStatus(Constants.H5OrderStatus.COMPLETED);
            optHistory.setCreateTime(optDate);
            optHistory.setUpdateTime(optDate);
            orderOperateHistoryMapper.insert(optHistory);
        });
    }

    @Transactional(rollbackFor = Exception.class)
    @Lock4j(name = "h5_oms_order_complete:", keys = "#orderId")
    public String orderComplete(Long orderId) {
        log.info("确认收货，订单id：{}", orderId);
        LocalDateTime optDate = LocalDateTime.now();
        Order order = orderMapper.selectById(orderId);
        OrderItem queryOrderItem = new OrderItem();
        queryOrderItem.setOrderId(orderId);
        List<OrderItem> orderItemList = orderItemMapper.selectByEntity(queryOrderItem);
        if (order == null || CollUtil.isEmpty(orderItemList)) {
            throw new ServerException("未查询到订单信息");
        }
        // 只有【待收货】状态才能确认
        if (!order.getStatus().equals(Constants.H5OrderStatus.DELIVERED)) {
            throw new ServerException("订单状态已改变，请刷新");
        }
        order.setStatus(Constants.H5OrderStatus.COMPLETED);
        order.setReceiveTime(optDate);
        order.setConfirmStatus(1);
        order.setUpdateTime(optDate);
        order.setUpdateBy(SecurityUtil.getLocalMember().getId());
        orderMapper.updateById(order);
        //创建订单操作记录
        OrderOperateHistory optHistory = getOrderOperateHistory(order, Constants.H5OrderStatus.COMPLETED, optDate);
        orderOperateHistoryMapper.insert(optHistory);
        return order.getOrderSn();
    }

    /**
     * 统计待付款、待发货、待收货和售后订单数量
     *
     * @param memberId 会员ID
     * @return {@link CountOrderVO }
     */
    public CountOrderVO orderNumCount(Long memberId) {
        return orderMapper.countByStatusAndMemberId(memberId);
    }

    @Transactional(rollbackFor = Exception.class)
    @Lock4j(name = "h5_oms_order_cancel:", keys = "request.idList[0]")
    public String orderBatchCancel(CancelOrderForm request) {
        LocalDateTime optDate = LocalDateTime.now();
        if (CollUtil.isEmpty(request.getIdList())) {
            throw new ServerException("未指定需要取消的订单号");
        }
        QueryWrapper<Order> orderQw = new QueryWrapper<>();
        orderQw.in("id", request.getIdList());
        List<Order> orderList = orderMapper.selectList(orderQw);
        if (orderList.size() < request.getIdList().size()) {
            throw new ServerException("未查询到订单信息");
        }
        //查orderItem
        QueryWrapper<OrderItem> qw = new QueryWrapper<>();
        qw.in("order_id", request.getIdList());
        List<OrderItem> orderItem = orderItemMapper.selectList(qw);
        if (CollUtil.isEmpty(orderItem)) {
            throw new ServerException("未查询到订单信息");
        }
        long count = orderList.stream().filter(it -> !Constants.H5OrderStatus.UN_PAY.equals(it.getStatus())).count();
        if (count > 0) {
            throw new ServerException("订单状态已更新，请刷新页面");
        }
        List<OrderOperateHistory> addHistoryList = new ArrayList<>();
        orderList.forEach(item -> {
            item.setStatus(Constants.H5OrderStatus.CLOSED);
            item.setUpdateTime(optDate);
            item.setUpdateBy(SecurityUtil.getMemberId());
            OrderOperateHistory history = getOrderOperateHistory(item, Constants.H5OrderStatus.CLOSED, optDate);
            addHistoryList.add(history);
        });
        //取消订单
        int rows = orderMapper.cancelBatch(orderList);
        if (rows < 1) {
            throw new ServerException("更改订单状态失败");
        }
        orderItem.stream().collect(Collectors.groupingBy(OrderItem::getSkuId)).forEach((k, v) -> {
            AtomicReference<Integer> totalCount = new AtomicReference<>(0);
            v.forEach(it -> totalCount.updateAndGet(v1 -> v1 + it.getQuantity()));
            skuMapper.updateStockById(k, optDate, -1 * totalCount.get());
        });

        //创建订单操作记录
        boolean flag = orderOperateHistoryService.saveBatch(addHistoryList);
        if (!flag) {
            throw new ServerException("创建订单操作记录失败");
        }
        //判断是否使用优惠券，有的话，把优惠券还回去
        List<Long> couponIdList = orderList.stream().map(Order::getMemberCouponId).filter(Objects::nonNull).collect(Collectors.toList());
        if (!CollUtil.isEmpty(couponIdList)) {
            memberCouponService.backCoupon(couponIdList);
        }
        return "取消订单成功";
    }

    /**
     * 订单支付
     *
     * @param req 支付请求
     * @return {@link OrderPayVO }
     */
    @Transactional(rollbackFor = Exception.class)
    @Lock4j(name = "h5_oms_order_pay:", keys = "#req.payId")
    public OrderPayVO orderPay(OrderPayForm req) {
        QueryWrapper<Order> qw = new QueryWrapper<>();
        qw.eq("pay_id", req.getPayId());
        qw.eq("status", 0);
        List<Order> orderList = orderMapper.selectList(qw);
        if (CollUtil.isEmpty(orderList)) {
            throw new ServerException("没有待支付的订单");
        }
        QueryWrapper<MemberWechat> memberWechatQw = new QueryWrapper<>();
        memberWechatQw.eq("member_id", SecurityUtil.getMemberId());
        MemberWechat memberWechat = memberWechatMapper.selectOne(memberWechatQw);
        if (memberWechat == null) {
            throw new ServerException("获取用户openId失败");
        }
        String openId = null;
        String appId = null;
        //公众号支付流程
        if (req.getWechatType() == 1) {
            if (StrUtil.isBlank(memberWechat.getOpenid())) {
                throw new ServerException("获取用户openId失败");
            }
            openId = memberWechat.getOpenid();
            appId = wechatPayData.getAppId();
        }
        //小程序支付流程
        if (req.getWechatType() == 2) {
            if (StrUtil.isBlank(memberWechat.getRoutineOpenid())) {
                throw new ServerException("获取用户openId失败");
            }
            openId = memberWechat.getRoutineOpenid();
            appId = wechatPayData.getMiniProgramAppId();
        }
        QueryWrapper<OrderItem> orderItemQw = new QueryWrapper<>();
        orderItemQw.eq("order_id", orderList.get(0).getId());
        List<OrderItem> orderItemList = orderItemMapper.selectList(orderItemQw);
        String orderDesc = orderItemList.get(0).getProductName().substring(0, Math.min(40, orderItemList.get(0).getProductName().length()));
        //保存微信支付历史
        LocalDateTime optDate = LocalDateTime.now();
        QueryWrapper<WechatPaymentHistory> wxPaymentQw = new QueryWrapper<>();
        wxPaymentQw.eq("order_id", orderList.get(0).getPayId());
        wxPaymentQw.eq("op_type", Constants.PaymentOpType.PAY);
        WechatPaymentHistory wechatPaymentHistory = wechatPaymentHistoryMapper.selectOne(wxPaymentQw);
        if (wechatPaymentHistory == null) {
            wechatPaymentHistory = new WechatPaymentHistory();
            wechatPaymentHistory.setOrderId(orderList.get(0).getPayId());
            wechatPaymentHistory.setMemberId(SecurityUtil.getMemberId());
            wechatPaymentHistory.setOpenid(openId);
            wechatPaymentHistory.setTitle(orderItemList.get(0).getProductName());
            wechatPaymentHistory.setMoney(orderList.get(0).getPayAmount());
            wechatPaymentHistory.setOpType(Constants.PaymentOpType.PAY);
            wechatPaymentHistory.setPaymentStatus(0);
            wechatPaymentHistory.setCreateBy(SecurityUtil.getMemberId());
            wechatPaymentHistory.setCreateTime(optDate);
            wechatPaymentHistory.setUpdateBy(SecurityUtil.getMemberId());
            wechatPaymentHistory.setUpdateTime(optDate);
            wechatPaymentHistoryMapper.insert(wechatPaymentHistory);
        } else {
            wechatPaymentHistory.setMoney(orderList.get(0).getPayAmount());
            wechatPaymentHistoryMapper.updateById(wechatPaymentHistory);
        }
        //请开启微信支付 wechat.enabled=true
        //调用wx的jsapi拿prepayId，返回签名等信息
        String prepayId = wechatPayService.jsapiPay(String.valueOf(req.getPayId()), orderDesc, Integer.valueOf(orderList.stream()
                                                                                                                        .map(Order::getPayAmount)
                                                                                                                        .reduce(BigDecimal.ZERO, BigDecimal::add)
                                                                                                                        .multiply(new BigDecimal(100))
                                                                                                                        .stripTrailingZeros()
                                                                                                                        .toPlainString()), openId, SecurityUtil.getMemberId(), appId);
        OrderPayVO response = new OrderPayVO();
        response.setPayType(2);
        String nonceStr = WechatPayUtil.generateNonceStr();
        long timeStamp = WechatPayUtil.getCurrentTimestamp();
        prepayId = "prepay_id=" + prepayId;
        String signType = "RSA";
        String paySign;
        String signatureStr = Stream.of(appId, String.valueOf(timeStamp), nonceStr, prepayId).collect(Collectors.joining("\n", "", "\n"));
        try {
            paySign = WechatPayUtil.getSign(signatureStr, wechatPayData.getPrivateKeyPath());
        } catch (Exception e) {
            throw new ServerException("支付失败");
        }
        response.setAppId(appId);
        response.setTimeStamp(String.valueOf(timeStamp));
        response.setNonceStr(nonceStr);
        response.setSignType(signType);
        response.setPackage_(prepayId);
        response.setPaySign(paySign);
        return response;
    }

    /**
     * 支付回调方法
     *
     * @param messageDTO 消息 DTO
     */
    @Lock4j(name = "h5_oms_order_pay_notify", keys = "#messageDTO.outTradeNo")
    @Transactional(rollbackFor = Exception.class)
    public void payCallBack(PayNotifyMessageDTO messageDTO) {
        log.info("【订单支付回调】{}", Json.toStr(messageDTO));
        LocalDateTime optDate = LocalDateTime.now();
        try {
            //先判断回信回调的是否未success
            if (!Transaction.TradeStateEnum.SUCCESS.equals(messageDTO.getTradeStatus())) {
                log.error("【订单支付回调】订单状态不是支付成功状态{}", messageDTO.getTradeStatus());
                return;
            }
            QueryWrapper<WechatPaymentHistory> paymentWrapper = new QueryWrapper<>();
            paymentWrapper.eq("order_id", messageDTO.getOutTradeNo());
            paymentWrapper.eq("op_type", Constants.PaymentOpType.PAY);
            WechatPaymentHistory paymentHistory = wechatPaymentHistoryMapper.selectOne(paymentWrapper);
            if (!paymentHistory.getPaymentStatus().equals(Constants.PaymentStatus.INCOMPLETE)) {
                log.info("【订单支付回调】支付订单不是未支付状态，不再处理orderId{}status{}", paymentHistory.getOrderId(), paymentHistory.getPaymentStatus());
                return;
            }
            QueryWrapper<Order> orderQw = new QueryWrapper<>();
            orderQw.eq("pay_id", messageDTO.getOutTradeNo());
            orderQw.eq("status", OrderStatus.UN_PAY.getType());
            List<Order> orderList = orderMapper.selectList(orderQw);
            orderList.forEach(order -> {
                order.setPaymentTime(messageDTO.getPayTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
                order.setStatus(OrderStatus.NOT_DELIVERED.getType());
                orderMapper.updateById(order);
                OrderOperateHistory optHistory = getOrderOperateHistory(order, OrderStatus.NOT_DELIVERED.getType(), optDate);
                orderOperateHistoryMapper.insert(optHistory);
            });
            UpdateWrapper<WechatPaymentHistory> paymentHistoryUpdateWrapper = new UpdateWrapper<>();
            paymentHistoryUpdateWrapper.eq("order_id", messageDTO.getOutTradeNo()).set("payment_id", messageDTO.getTradeNo())
                                       .set("payment_status", Constants.PaymentStatus.COMPLETE).set("update_time", optDate);
            wechatPaymentHistoryMapper.update(null, paymentHistoryUpdateWrapper);
        } catch (Exception e) {
            log.error("订单支付回调异常", e);
        }
    }

    @NotNull
    private static OrderOperateHistory getOrderOperateHistory(Order order, Integer orderStatus, LocalDateTime optDate) {
        OrderOperateHistory optHistory = new OrderOperateHistory();
        optHistory.setOrderId(order.getId());
        optHistory.setOrderSn(order.getOrderSn());
        optHistory.setOperateMan(SecurityUtil.getMemberName());
        optHistory.setOrderStatus(orderStatus);
        optHistory.setCreateTime(optDate);
        optHistory.setCreateBy(SecurityUtil.getMemberId());
        optHistory.setUpdateBy(SecurityUtil.getMemberId());
        optHistory.setUpdateTime(optDate);
        return optHistory;
    }

    /**
     * 申请售后
     *
     * @param applyRefundForm 申请退款参数
     * @return boolean
     */
    @Lock4j(name = "h5_oms_order_applyRefund:", keys = "#applyRefundForm.orderId")
    @Transactional(rollbackFor = Exception.class)
    public boolean applyRefund(ApplyRefundForm applyRefundForm) {
        Order order = createAfterSale(applyRefundForm);
        // 如果是未发货，系统自动退款
        if (order.getStatus().equals(OrderStatus.NOT_DELIVERED.getType())) {
            DealWithAftersaleForm req = new DealWithAftersaleForm();
            req.setOrderId(applyRefundForm.getOrderId());
            req.setOptType(1);
            aftersaleService.dealWith(req, order.getMemberId(), "直接发起退款");
        }
        return true;
    }

    private Order createAfterSale(ApplyRefundForm applyRefundForm) {
        Order order = orderMapper.selectById(applyRefundForm.getOrderId());
        //是否符合售后条件
        this.checkIfCanApplyRefund(order);
        LocalDateTime optDate = LocalDateTime.now();
        Long memberId = order.getMemberId();
        //创建售后单aftersale
        AfterSale addAfterSale = new AfterSale();
        addAfterSale.setId(IdUtil.getSnowflakeNextId());
        addAfterSale.setMemberId(order.getMemberId());
        addAfterSale.setOrderId(order.getId());
        addAfterSale.setReturnAmount(order.getPayAmount());
        addAfterSale.setType(applyRefundForm.getApplyRefundType());
        addAfterSale.setStatus(AfterSaleStatus.APPLY.getType());
        addAfterSale.setReason(applyRefundForm.getReason());
        addAfterSale.setQuantity(applyRefundForm.getQuantity());
        addAfterSale.setReason(applyRefundForm.getReason());
        addAfterSale.setDescription(applyRefundForm.getDescription());
        addAfterSale.setProofPics(applyRefundForm.getProofPics());
        addAfterSale.setCreateTime(optDate);
        addAfterSale.setCreateBy(memberId);
        addAfterSale.setUpdateTime(optDate);
        addAfterSale.setUpdateBy(memberId);
        int rows = aftersaleMapper.insert(addAfterSale);
        if (rows != 1) {
            throw new ServerException("插入订单售后失败");
        }
        //创建aftersale item
        QueryWrapper<OrderItem> orderItemQw = new QueryWrapper<>();
        orderItemQw.eq("order_id", order.getId());
        List<OrderItem> orderItemList = orderItemMapper.selectList(orderItemQw);
        List<AfterSaleItem> addAfterSaleItemList = new ArrayList<>();
        orderItemList.forEach(orderItem -> {
            AfterSaleItem aftersaleItem = new AfterSaleItem();
            aftersaleItem.setMemberId(memberId);
            aftersaleItem.setAftersaleId(addAfterSale.getId());
            aftersaleItem.setOrderId(orderItem.getOrderId());
            aftersaleItem.setOrderItemId(orderItem.getId());
            aftersaleItem.setReturnAmount(orderItem.getSalePrice().multiply(BigDecimal.valueOf(orderItem.getQuantity())));
            aftersaleItem.setQuantity(orderItem.getQuantity());
            aftersaleItem.setCreateTime(optDate);
            aftersaleItem.setCreateBy(memberId);
            aftersaleItem.setUpdateTime(optDate);
            aftersaleItem.setUpdateBy(memberId);
            addAfterSaleItemList.add(aftersaleItem);
        });
        rows = aftersaleItemMapper.insertBatch(addAfterSaleItemList);
        if (rows < 1) {
            throw new ServerException("创建售后订单item失败");
        }
        //更新订单
        UpdateWrapper<Order> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("id", order.getId()).set("aftersale_status", OrderRefundStatus.APPLY.getType()).set("update_time", optDate)
                     .set("update_by", memberId);
        rows = orderMapper.update(null, updateWrapper);
        if (rows < 1) {
            throw new ServerException("修改订单状态失败");
        }
        //创建订单操作记录
        OrderOperateHistory optHistory = getOrderOperateHistory(order, 11, optDate);
        rows = orderOperateHistoryMapper.insert(optHistory);
        if (rows < 1) {
            throw new ServerException("创建订单操作记录失败");
        }
        return order;
    }

    /**
     * check是否能售后 可售后的状态为：待发货、待收货、已完成
     *
     * @param order 订单
     */
    private void checkIfCanApplyRefund(Order order) {
        if (order == null) {
            throw new ServerException("为查询到订单信息");
        }
        Integer status = order.getStatus();
        boolean flag = OrderStatus.NOT_DELIVERED.getType().equals(status) || OrderStatus.DELIVERED.getType().equals(status) || OrderStatus.COMPLETE
                .getType().equals(status);
        if (!flag) {
            throw new ServerException("该订单无法申请售后");
        }
        if (OrderStatus.COMPLETE.getType().equals(order.getStatus()) && DateUtils.betweenDay(LocalDateTime.now(), order.getReceiveTime()) > 7) {
            throw new ServerException("订单确认收货时间已超过7天，无法申请售后");
        }
        if (OrderRefundStatus.APPLY.getType().equals(order.getAftersaleStatus()) || OrderRefundStatus.WAIT.getType()
                                                                                                          .equals(order.getAftersaleStatus())) {
            throw new ServerException("售后正在处理中");
        }
    }

    /**
     * 取消售后
     *
     * @param orderId 订单id
     * @return {@link String }
     */
    @Lock4j(name = "h5_oms_order_cancelRefund:", keys = "#orderId")
    @Transactional(rollbackFor = Exception.class)
    public String cancelRefund(Long orderId) {
        log.info("【取消售后】订单id：{}", orderId);
        Order order = orderMapper.selectById(orderId);
        if (order == null) {
            throw new ServerException("未查询到该订单");
        }
        //查询是否有（待处理和退货中）售后单
        QueryWrapper<AfterSale> afterSaleQw = new QueryWrapper<>();
        afterSaleQw.eq("order_id", orderId);
        afterSaleQw.in("status", Arrays.asList(AfterSaleStatus.APPLY.getType(), AfterSaleStatus.WAIT.getType()));
        AfterSale aftersale = aftersaleMapper.selectOne(afterSaleQw);
        if (aftersale == null) {
            throw new ServerException("无售后单");
        }
        if (OrderRefundStatus.SUCCESS.getType().equals(order.getAftersaleStatus())) {
            throw new ServerException("已退款成功");
        }
        LocalDateTime optDate = LocalDateTime.now();
        //更新售后单状态
        UpdateWrapper<AfterSale> aftersaleUpdateWrapper = new UpdateWrapper<>();
        aftersaleUpdateWrapper.eq("id", aftersale.getId());
        aftersaleUpdateWrapper.set("status", AfterSaleStatus.CANCEL.getType());
        aftersaleUpdateWrapper.set("update_time", optDate);
        aftersaleUpdateWrapper.set("update_by", SecurityUtil.getMemberId());
        int rows = aftersaleMapper.update(null, aftersaleUpdateWrapper);
        if (rows < 1) {
            throw new ServerException("更新售后单失败");
        }
        //更新订单售后状态
        // 更新订单
        UpdateWrapper<Order> updateOrderWrapper = new UpdateWrapper<>();
        updateOrderWrapper.eq("id", orderId).set("aftersale_status", OrderRefundStatus.NO_REFUND.getType()).set("update_time", optDate)
                          .set("update_by", SecurityUtil.getMemberId());
        rows = orderMapper.update(null, updateOrderWrapper);
        if (rows != 1) {
            throw new ServerException("更新订单状态失败");
        }
        return "售后取消成功";
    }

    /**
     * 售后订单详情
     *
     * @param orderId 订单id
     * @return {@link AfterSaleRefundInfoVO }
     */
    public AfterSaleRefundInfoVO refundOrderDetail(Long orderId) {
        QueryWrapper<AfterSale> afterSaleQw = new QueryWrapper<>();
        afterSaleQw.eq("order_id", orderId);
        afterSaleQw.orderByDesc("create_time");
        afterSaleQw.last("limit 1");
        AfterSale aftersale = aftersaleMapper.selectOne(afterSaleQw);
        if (aftersale == null) {
            throw new ServerException("未查询到售后订单");
        }
        //查一下售后订单item
        QueryWrapper<AfterSaleItem> afterSaleItemQw = new QueryWrapper<>();
        afterSaleItemQw.eq("aftersale_id", aftersale.getId());
        List<AfterSaleItem> afterSaleItemList = aftersaleItemMapper.selectList(afterSaleItemQw);
        List<Long> orderItemIdList = afterSaleItemList.stream().map(AfterSaleItem::getOrderItemId).collect(Collectors.toList());
        //再去查orderItem
        QueryWrapper<OrderItem> orderItemQw = new QueryWrapper<>();
        orderItemQw.in("id", orderItemIdList);
        List<OrderItem> orderItemList = orderItemMapper.selectList(orderItemQw);
        AfterSaleRefundInfoVO vo = new AfterSaleRefundInfoVO();
        BeanUtils.copyProperties(aftersale, vo);
        vo.setAftersaleItemList(BeanUtil.copyToList(afterSaleItemList, AfterSaleItemVO.class));
        vo.setOrderItemList(BeanUtil.copyToList(orderItemList, OrderItemVO.class));
        return vo;
    }


    @Lock4j(name = "h5_oms_order_delivery:", keys = "#req.orderId")
    public String delivery(@Valid DeliveryReq req) {
        log.info("用户提交退货单号，提交的数据{}：", Json.toStr(req));
        Order order = this.selectById(req.getOrderId());
        QueryWrapper<AfterSale> itemQw = new QueryWrapper<>();
        itemQw.eq("order_id", req.getOrderId());
        itemQw.in("status", Arrays.asList(AfterSaleStatus.APPLY.getType(), AfterSaleStatus.WAIT.getType()));
        AfterSale aftersale = aftersaleMapper.selectOne(itemQw);
        if (order == null || aftersale == null) {
            throw new ServerException("未查询到订单信息");
        }
        //仅退款不需要退货
        if (aftersale.getType() == 1) {
            throw new ServerException("仅退款不需要退货");
        }
        if (!aftersale.getStatus().equals(AfterSaleStatus.WAIT.getType())) {
            throw new ServerException("当前状态不可退货");
        }
        //更新退款单
        aftersale.setRefundWpCode(req.getDeliveryCompanyCode());
        aftersale.setRefundWaybillCode(req.getDeliverySn());
        aftersaleMapper.updateById(aftersale);
        return "";
    }


    public Order selectById(Long orderId) {
        return orderMapper.selectById(orderId);
    }
}
